import { Inject, Provide } from "@midwayjs/core";
import { UploadFileInfo } from "@midwayjs/upload";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm";
import { BblAttach } from "../entity/attach.entity";
import { Utils } from "../utils";
import { AttachDto } from "../dto/att.dto";
import * as path from "path";
import * as fs from "fs";
import { CosService } from "./cos.service";

@Provide()
export class AttachService {
  @Inject()
  utils: Utils;

  @Inject()
  cosService: CosService;

  /**
   * 附件驱动模型
   */
  @InjectEntityModel(BblAttach)
  attModel: Repository<BblAttach>;

  /**
   * 上传二进制数据到腾讯云COS
   * @param buffer 文件二进制数据
   * @param fileName 文件名（包含扩展名）
   * @param contentType 文件MIME类型
   * @param savePath 可选保存路径
   */
  async putCosBufferObject(
    buffer: Buffer,
    fileName: string,
    contentType: string,
    savePath?: string
  ) {
    const result = await this.cosService.pubBufferObject(
      buffer,
      fileName,
      contentType,
      savePath
    );

    if (result.success) {
      const att = new BblAttach();
      att.attId = this.utils.snowFlake.generate();
      att.attName = result.data.cos_name;
      att.attMimeType = contentType;
      att.attState = "1";
      att.attStorageType = "1";
      att.attPath = result.data.cos_url;
      att.attCosKey = result.data.cos_key;

      // 从文件名中提取扩展名
      const exts = fileName.split(".");
      att.attExt = exts.length > 1 ? exts[exts.length - 1] : "";

      const res = await this.attModel.save(att);
      return this.utils.response.success({ data: res });
    }
    return this.utils.response.fail({ data: result.data });
  }

  /**
   * 上传文件到腾讯云COS
   * @param file 上传的文件对象
   * @param savePath 可选，保存路径
   */
  async putCosFileObject(file: UploadFileInfo<any>, savePath?: string) {
    const result = await this.cosService.putFileObject(file, savePath);
    if (result.success) {
      const att = new BblAttach();
      att.attId = this.utils.snowFlake.generate();
      att.attName = result.data.cos_name;
      att.attMimeType = file.mimeType;
      att.attState = "1";
      att.attStorageType = "1";
      att.attPath = result.data.cos_url;
      att.attCosKey = result.data.cos_key;

      const exts = file.data.toString().split(".");
      att.attExt = exts[exts.length - 1];

      const res = await this.attModel.save(att);
      return this.utils.response.success({ data: res });
    } else {
      return this.utils.response.fail({ data: result.data });
    }
  }

  async save(att: BblAttach | BblAttach[]) {
    if (!Array.isArray(att)) {
      att = [att];
    }
    return await this.attModel.save(att);
  }

  async upload(files: UploadFileInfo<any>[]) {
    const dtos: AttachDto[] = [];
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      const att = new BblAttach();
      att.attId = this.utils.uuid();
      att.attName = file.filename;
      att.attTempPath = file.data.toString();
      att.attMimeType = file.mimeType;
      att.attState = "0";
      att.attId = this.utils.uuid();
      const exts = file.data.toString().split(".");
      att.attExt = exts[exts.length - 1];
      const res = await this.attModel.save(att);
      const dto = new AttachDto(res);
      dtos.push(dto);
    }
    return this.utils.service.success(dtos);
  }

  async get_att_by_id(id: string) {
    const att = await this.attModel.findOne({
      where: {
        attId: id
      }
    });
    return this.utils.service.success(att);
  }

  /**
   * 临时文件转移到上传文件夹
   * @param attIds
   */
  async tmp_to_uploads(targets: BblAttach | BblAttach[]) {
    let atts;
    if (!Array.isArray(targets)) {
      atts = [targets];
    } else {
      atts = targets;
    }

    const uploadDir = path.resolve(process.cwd(), "uploads");

    atts.forEach((file) => {
      if (file.attState !== "1") {
        const fileName = path.basename(file.attTempPath);
        const attPath = path.resolve(uploadDir, fileName);
        if (fs.existsSync(file.attTempPath)) {
          fs.copyFileSync(file.attTempPath, attPath);
          fs.unlinkSync(file.attTempPath);
        }

        file.attTempPath = "";
        file.attPath = attPath;
        file.attState = "1";
      }
    });
    await this.attModel.save(atts);
  }

  async remove(targets: BblAttach | BblAttach[]) {
    let atts;
    if (!Array.isArray(targets)) {
      atts = [targets];
    } else {
      atts = targets;
    }

    atts.forEach((file) => {
      fs.existsSync(file.attPath) && fs.unlinkSync(file.attPath);
    });

    await this.attModel.remove(atts);
  }

  async remove_by_id(attId: string) {
    const att = await this.attModel.findOne({
      where: {
        attId
      }
    });
    if (att) {
      await this.remove(att);
    }
  }
}
